`include "define.svh"

module mem_wrap(
    input wire                              clk,
    input wire                              rstn,
    input wire                              ex_stalled,
    input wire                              ctrl_stall,
    input wire [`PC_WIDTH - 1 : 0]          debug_pc_i,
    input wire                              data_data_ok,
    
    input wire [3 : 0]                      data2reg_en,        // clk
    input wire                              data2reg_signed,    // clk
    input wire [4 : 0]                      data2reg_shift,     // clk
    
    input wire [`REG_WIDTH - 1 : 0]         rdata_i,
    
    input wire [`REG_ADDR_WIDTH - 1 : 0]    wregaddr_i,         // clk
    input wire                              wregenable_i,       // clk
    input wire [`REG_WIDTH - 1 : 0]         wregdata_i,         // clk
    output reg [`REG_ADDR_WIDTH - 1 : 0]    wregaddr_o,
    output reg                              wregenable_o,
    output reg [`REG_WIDTH - 1 : 0]         wregdata_o,
    
    output reg [`PC_WIDTH - 1 : 0]          debug_pc_o
    
);
    
    reg [`REG_ADDR_WIDTH - 1 : 0]   wregaddr;
    reg                             wregenable;
    reg [`REG_WIDTH - 1 : 0]        wregdata;
    reg [3 : 0]                     data2regen;
    reg                             data2regsigned;
    reg [4 : 0]                     data2regshift;
    reg [`REG_WIDTH - 1 : 0]        rdata;
    
    always_ff @(posedge clk) begin
        if (rstn == `reset) begin
            wregenable <= `false;
            wregaddr <= `ZERO_REG_ADDR;
            wregdata <= `ZERO_REG;
            debug_pc_o <= `NOP_PC;
            data2regen <= 4'b0000;
            data2regsigned <= `false;
            data2regshift <= 5'b00000;
            rdata <= `ZERO_REG;
        end else if (ctrl_stall) begin
            wregenable <= wregenable;
            wregaddr <= wregaddr;
            wregdata <= wregdata;
            debug_pc_o <= debug_pc_o;
            data2regen <= data2regen;
            data2regsigned <= data2regsigned;
            data2regshift <= data2regshift;
            rdata <= rdata;
        end else if (ex_stalled) begin
            wregenable <= `false;
            wregaddr <= `ZERO_REG_ADDR;
            wregdata <= `ZERO_REG;
            debug_pc_o <= `NOP_PC;
            data2regen <= 4'b0000;
            data2regsigned <= `false;
            data2regshift <= 5'b00000;
            rdata <= `ZERO_REG;
        end else begin
            data2regen <= data2reg_en;
            data2regsigned <= data2reg_signed;
            data2regshift <= data2reg_shift;
            wregenable <= wregenable_i;
            wregaddr <= wregaddr_i;
            wregdata <= wregdata_i;
            debug_pc_o <= debug_pc_i;
            rdata <= rdata_i;
        end
    end
    
    wire [`REG_WIDTH - 1 : 0]       shifted_data = rdata >> data2regshift;

    always_comb begin
        wregenable_o = wregenable;
        wregaddr_o = wregaddr;
        case ({data2regsigned, data2regen})
            5'b00001:       wregdata_o <= {24'h000000, shifted_data[7 : 0]};
            5'b10001:       wregdata_o <= {{24{shifted_data[7]}}, shifted_data[7 : 0]};
            5'b00011:       wregdata_o <= {16'h0000, shifted_data[15 : 0]};
            5'b10011:       wregdata_o <= {{16{shifted_data[15]}}, shifted_data[15 : 0]};
            5'b11111:       wregdata_o <= shifted_data;
            default:        wregdata_o <= wregdata;
        endcase
    end
    
endmodule
